// TMake语法分析器
// 负责将词法分析得到的标记序列转换为抽象语法树(AST)

import { TMakeASTNode, CompilerError, ASTNodeType, SwitchStatementNode, CaseClauseNode, DefaultClauseNode } from './types';

/**
 * TMake语法分析器类
 * 将词法分析器生成的标记序列解析为结构化的抽象语法树
 */
export class TMakeParser {
    private tokens: TMakeASTNode[];    // 输入的标记序列
    private position: number = 0;      // 当前解析位置
    private errors: CompilerError[] = []; // 语法错误集合

    /**
     * 构造函数
     * @param tokens 从词法分析器获取的标记数组
     */
    constructor(tokens: TMakeASTNode[]) {
        this.tokens = tokens;
    }

    /**
     * 获取语法分析过程中收集的错误
     * @returns 错误数组
     */
    public getErrors(): CompilerError[] {
        return this.errors;
    }

    /**
     * 查看当前位置的标记但不消费
     * @returns 当前位置的标记或EOF标记
     */
    private peek(): TMakeASTNode {
        return this.position < this.tokens.length ? this.tokens[this.position] : { type: 'eof', value: '' };
    }

    /**
     * 消费当前位置的标记并返回
     * 可选地验证标记类型是否符合预期
     * @param expectedType 期望的标记类型
     * @returns 消费的标记
     */
    private consume(expectedType?: string): TMakeASTNode {
        if (this.position >= this.tokens.length) {
            const lastToken = this.tokens[this.tokens.length - 1];
            this.errors.push({
                type: 'syntax',
                message: '意外的文件结尾',
                line: lastToken?.line,
                column: lastToken?.column
            });
            return { type: 'eof', value: '' };
        }

        const token = this.tokens[this.position++];
        if (expectedType && token.type !== expectedType) {
            this.errors.push({
                type: 'syntax',
                message: `期望 ${expectedType}，但得到 ${token.type}`,
                line: token.line,
                column: token.column,
                token: token.value
            });
        }
        return token;
    }

    /**
     * 期望当前位置的标记值符合预期
     * 如果符合则消费该标记，否则记录错误
     * @param value 期望的标记值
     * @returns 是否符合预期
     */
    private expect(value: string): boolean {
        const token = this.peek();
        if (token.value === value) {
            this.consume();
            return true;
        } else {
            this.errors.push({
                type: 'syntax',
                message: `期望 '${value}'，但得到 '${token.value}'`,
                line: token.line,
                column: token.column,
                token: token.value
            });
            return false;
        }
    }

    /**
     * 跳过当前位置到分号的所有标记
     * 用于错误恢复机制
     */
    private skipToSemicolon(): void {
        while (this.position < this.tokens.length && this.peek().value !== ';') {
            this.consume();
        }
        if (this.peek().value === ';') {
            this.consume('punctuation'); // 消费分号
        }
    }

    /**
     * 解析数组表达式
     * 支持逗号分隔的元素列表
     * @returns 数组节点
     */
    private parseArray(): TMakeASTNode {
        const startToken = this.peek();
        this.consume('punctuation'); // 消费 [
        const elements: any[] = [];

        // 解析数组元素，直到遇到 ] 或文件结束
        while (this.position < this.tokens.length && this.peek().value !== ']') {
            // 跳过多余的逗号
            if (this.peek().value === ',') {
                this.consume('punctuation');
                continue;
            }

            try {
                const element = this.parseExpression();
                if (element) {
                    elements.push(element);
                }
            } catch (error) {
                // 错误恢复：跳过当前标记
                if (this.position < this.tokens.length && this.peek().value !== ']' && this.peek().value !== ',') {
                    this.consume();
                }
            }
        }

        // 消费数组结束符
        if (this.peek().value === ']') {
            this.consume('punctuation'); // 消费 ]
        } else {
            this.errors.push({
                type: 'syntax',
                message: '数组未正确终止，缺少 ]',
                line: startToken.line,
                column: startToken.column
            });
        }

        return {
            type: 'array',
            value: elements,
            line: startToken.line,
            column: startToken.column
        };
    }

    /**
     * 解析表达式
     * 处理字符串、数字、标识符、函数调用和数组
     * @returns 表达式节点
     */
    private parseExpression(): TMakeASTNode {
        const token = this.peek();

        if (token.type === 'eof') {
            throw new Error('表达式位置遇到文件结尾');
        }

        // 处理字符串字面量
        if (token.type === 'string') {
            const stringToken = this.consume('string');
            return {
                ...stringToken,
                rawValue: stringToken.value
            };
        } 
        // 处理数字字面量
        else if (token.type === 'number') {
            const numberToken = this.consume('number');
            const numValue = parseFloat(numberToken.value);
            return {
                ...numberToken,
                rawValue: isNaN(numValue) ? numberToken.value : numValue
            };
        } 
        // 处理标识符和函数调用
        else if (token.type === 'identifier') {
            const identifierToken = this.consume('identifier');
            const nextToken = this.peek();

            // 检查是否为函数调用
            if (nextToken && nextToken.value === '(') {
                const functionCall: TMakeASTNode = {
                    type: 'function_call',
                    value: identifierToken.value,
                    params: [],
                    line: identifierToken.line,
                    column: identifierToken.column
                };

                this.consume('punctuation'); // 消费 (

                // 解析函数参数
                while (this.position < this.tokens.length && this.peek().value !== ')') {
                    if (this.peek().value === ',') {
                        this.consume('punctuation');
                        continue;
                    }

                    const param = this.parseExpression();
                    if (param) {
                        functionCall.params!.push(param);
                    }
                }

                // 消费右括号
                if (this.peek().value === ')') {
                    this.consume('punctuation'); // 消费 )
                } else {
                    this.errors.push({
                        type: 'syntax',
                        message: `函数调用未正确终止，缺少 )`,
                        line: identifierToken.line,
                        column: identifierToken.column,
                        token: identifierToken.value
                    });
                }

                return functionCall;
            } 
            // 普通标识符
            else {
                return {
                    ...identifierToken,
                    rawValue: identifierToken.value
                };
            }
        } 
        // 处理数组
        else if (token.value === '[') {
            return this.parseArray();
        } 
        // 无法识别的表达式
        else {
            this.errors.push({
                type: 'syntax',
                message: `表达式位置出现意外的token: ${token.type} '${token.value}'`,
                line: token.line,
                column: token.column,
                token: token.value
            });
            this.consume();
            return {
                type: 'error',
                value: token.value,
                line: token.line,
                column: token.column
            };
        }
    }

    /**
     * 解析函数调用语句
     * 支持参数列表和错误恢复
     * @returns 函数调用节点
     */
    private parseFunctionCall(): TMakeASTNode {
        const identifier = this.consume('identifier');

        // 期望左括号
        if (!this.expect('(')) {
            this.skipToSemicolon();
            return {
                type: 'function_call',
                value: identifier.value,
                params: [],
                line: identifier.line,
                column: identifier.column
            };
        }

        const params: any[] = [];

        // 处理空参数列表
        if (this.peek().value === ')') {
            this.consume('punctuation');
            return {
                type: 'function_call',
                value: identifier.value,
                params: [],
                line: identifier.line,
                column: identifier.column
            };
        }
        
        // 解析参数列表
        while (this.position < this.tokens.length && this.peek().value !== ')') {
            if (this.peek().value === ',') {
                this.consume('punctuation');
                continue;
            }

            try {
                // 解析参数表达式
                const param = this.parseExpression();
                if (param && param.type !== 'error') {
                    params.push(param);
                }
            } catch (error) {
                // 错误恢复
                if (this.position < this.tokens.length &&
                    this.peek().value !== ')' && this.peek().value !== ',') {
                    this.consume();
                }
            }
        }

        // 处理右括号
        if (this.peek().value === ')') {
            this.consume('punctuation');
        } else {
            this.errors.push({
                type: 'syntax',
                message: `函数调用未正确终止，缺少 )`,
                line: identifier.line,
                column: identifier.column,
                token: identifier.value
            });
            this.skipToSemicolon();
        }

        return {
            type: 'function_call',
            value: identifier.value,
            params,
            line: identifier.line,
            column: identifier.column
        };
    }

    /**
     * 解析switch语句
     * 使用中文关键词"假如"、"是"、"否则"和"结束假如"
     * @returns switch语句节点
     */
    private parseSwitchStatement(): SwitchStatementNode {
        const switchToken = this.consume(); // 消费 "假如"，不再强制类型检查

        // 解析表达式
        let expression: TMakeASTNode;
        try {
            expression = this.parseExpression();
        } catch (error) {
            this.errors.push({
                type: 'syntax',
                message: 'switch语句表达式解析失败',
                line: switchToken.line,
                column: switchToken.column
            });
            expression = {
                type: 'error',
                value: 'expression_error',
                line: switchToken.line,
                column: switchToken.column
            };
        }

        const cases: CaseClauseNode[] = [];
        let defaultCase: DefaultClauseNode | undefined;
        
        // 检查是否到达"结束 假如"
        const isEndSwitch = () => {
            if (this.position + 1 >= this.tokens.length) return false;
            return this.peek().value === '结束' && this.tokens[this.position + 1].value === '假如';
        };

        // 解析case分支
        while (this.position < this.tokens.length) {
            // 检查是否到达"结束假如"
            if (isEndSwitch()) {
                break;
            }
            
            const caseToken = this.peek();
            
            if (caseToken.value === '是') {
                this.consume(); // 消费 "是"，不再强制类型检查
                
                try {
                    const caseValue = this.parseExpression();
                    const caseBody: TMakeASTNode[] = [];
                    
                    // 解析case体，直到遇到下一个case、default或结束标记
                    while (this.position < this.tokens.length) {
                        const nextToken = this.peek();
                        if (nextToken.value === '是' || nextToken.value === '否则' || 
                            isEndSwitch()) {
                            break;
                        }
                        
                        try {
                            const statement = this.parseStatement();
                            if (statement && statement.type !== 'error') {
                                caseBody.push(statement);
                            }
                        } catch (error) {
                            // 错误恢复
                            if (this.position < this.tokens.length) {
                                const recoveryToken = this.peek();
                                if (recoveryToken.value !== '是' && recoveryToken.value !== '否则' && 
                                    !isEndSwitch()) {
                                    this.consume();
                                }
                            }
                        }
                    }
                    
                    // 创建符合CaseClauseNode接口的节点
                    const caseClause: CaseClauseNode = {
                        type: ASTNodeType.CASE_CLAUSE,
                        test: caseValue,
                        consequent: caseBody,
                        line: caseToken.line,
                        column: caseToken.column
                    };
                    
                    cases.push(caseClause);
                } catch (error) {
                    this.errors.push({
                        type: 'syntax',
                        message: 'switch case解析失败',
                        line: caseToken.line,
                        column: caseToken.column
                    });
                }
            } else if (caseToken.value === '否则') {
                this.consume(); // 消费 "否则"，不再强制类型检查
                
                try {
                    const defaultBody: TMakeASTNode[] = [];
                    
                    // 解析default体，直到遇到结束标记
                    while (this.position < this.tokens.length) {
                        if (isEndSwitch()) {
                            break;
                        }
                        
                        try {
                            const statement = this.parseStatement();
                            if (statement && statement.type !== 'error') {
                                defaultBody.push(statement);
                            }
                        } catch (error) {
                            // 错误恢复
                            if (this.position < this.tokens.length && 
                                !isEndSwitch()) {
                                this.consume();
                            }
                        }
                    }
                    
                    // 创建符合DefaultClauseNode接口的节点
                    defaultCase = {
                        type: ASTNodeType.DEFAULT_CLAUSE,
                        consequent: defaultBody,
                        line: caseToken.line,
                        column: caseToken.column
                    };
                } catch (error) {
                    this.errors.push({
                        type: 'syntax',
                        message: 'switch default解析失败',
                        line: caseToken.line,
                        column: caseToken.column
                    });
                }
            } else {
                // 处理无法识别的token
                if (isEndSwitch()) {
                    break;
                }
                this.consume();
            }
        }

        // 处理结束标记
        if (isEndSwitch()) {
            this.consume(); // 消费 "结束"
            this.consume(); // 消费 "假如"
        } else {
            this.errors.push({
                type: 'syntax',
                message: 'switch语句未正确终止，缺少 结束假如',
                line: switchToken.line,
                column: switchToken.column
            });
            
            // 错误恢复：尝试找到结束标记
            while (this.position < this.tokens.length) {
                // 如果找到了"结束"关键词，检查下一个是否是"假如"
                if (this.peek().value === '结束' && this.position + 1 < this.tokens.length && 
                    this.tokens[this.position + 1].value === '假如') {
                    break;
                }
                this.consume();
            }
            
            // 如果找到了结束标记，尝试消费它们
            if (isEndSwitch()) {
                this.consume(); // 消费 "结束"
                this.consume(); // 消费 "假如"
            }
        }

        // 返回符合SwitchStatementNode接口的节点
        return {
            type: ASTNodeType.SWITCH_STATEMENT,
            expression,
            cases,
            defaultCase,
            line: switchToken.line,
            column: switchToken.column
        };
    }

    /**
     * 解析if语句
     * 使用中文关键词"如果"和"结束如果"
     * @returns if语句节点
     */
    private parseIfStatement(): TMakeASTNode {
        const ifToken = this.consume('identifier'); // 消费 "如果"

        // 解析条件表达式（这里使用函数调用作为条件）
        let condition: TMakeASTNode;
        try {
            condition = this.parseFunctionCall();
        } catch (error) {
            this.errors.push({
                type: 'syntax',
                message: 'if语句条件解析失败',
                line: ifToken.line,
                column: ifToken.column
            });
            condition = {
                type: 'error',
                value: 'condition_error',
                line: ifToken.line,
                column: ifToken.column
            };
        }

        const body: TMakeASTNode[] = [];
        
        // 检查是否到达"结束如果"
        const isEndIf = () => this.position < this.tokens.length && this.peek().value === '结束如果';

        // 解析if语句体
        while (this.position < this.tokens.length && !isEndIf()) {
            try {
                const statement = this.parseStatement();
                if (statement && statement.type !== 'error') {
                    body.push(statement);
                }
            } catch (error) {
                // 错误恢复
                if (this.position < this.tokens.length && !isEndIf()) {
                    this.consume();
                }
            }
        }

        // 处理结束标记
        if (isEndIf()) {
            this.consume('identifier'); // 消费 "结束如果"
        } else {
            this.errors.push({
                type: 'syntax',
                message: 'if语句未正确终止，缺少 结束如果',
                line: ifToken.line,
                column: ifToken.column
            });
            
            // 错误恢复：尝试找到结束标记
            while (this.position < this.tokens.length &&
                this.peek().value !== '结束如果') {
                this.consume();
            }
            
            // 如果找到了结束标记，尝试消费它
            if (isEndIf()) {
                this.consume('identifier');
            }
        }

        return {
            type: 'if_statement',
            value: 'if',
            params: [condition],
            children: body,
            line: ifToken.line,
            column: ifToken.column
        };
    }

    /**
     * 解析语句
     * 处理if语句和函数调用语句
     * @returns 语句节点
     */
    private parseStatement(): TMakeASTNode {
        const token = this.peek();

        if (!token || token.type === 'eof') {
            throw new Error('语句位置遇到文件结尾');
        }

        // 处理switch语句（假如/是）
        if (token.value === '假如') {
            return this.parseSwitchStatement();
        }
        // 处理if语句
        else if (token.value === '如果') {
            return this.parseIfStatement();
        } 
        // 处理函数调用语句（包括标识符和关键词）
        else if (token.type === 'identifier' || token.type === 'keyword') {
            // 对于关键词，我们需要先消费它，然后创建一个假的identifier节点传递给parseFunctionCall
            if (token.type === 'keyword') {
                const keywordToken = this.consume();
                // 创建一个identifier类型的节点用于parseFunctionCall
                const identifierNode: TMakeASTNode = {
                    type: 'identifier',
                    value: keywordToken.value,
                    line: keywordToken.line,
                    column: keywordToken.column
                };
                // 手动构建函数调用节点
                const functionCall: TMakeASTNode = {
                    type: 'function_call',
                    value: keywordToken.value,
                    params: [],
                    line: keywordToken.line,
                    column: keywordToken.column
                };
                
                // 期望左括号
                if (this.expect('(')) {
                    const params: any[] = [];
                    
                    // 处理空参数列表
                    if (this.peek().value === ')') {
                        this.consume('punctuation');
                    } else {
                        // 解析参数列表
                        while (this.position < this.tokens.length && this.peek().value !== ')') {
                            if (this.peek().value === ',') {
                                this.consume('punctuation');
                                continue;
                            }
                            
                            try {
                                const param = this.parseExpression();
                                if (param && param.type !== 'error') {
                                    params.push(param);
                                }
                            } catch (error) {
                                // 错误恢复
                                if (this.position < this.tokens.length &&
                                    this.peek().value !== ')' && this.peek().value !== ',') {
                                    this.consume();
                                }
                            }
                        }
                        
                        // 处理右括号
                        if (this.peek().value === ')') {
                            this.consume('punctuation');
                        } else {
                            this.errors.push({
                                type: 'syntax',
                                message: `函数调用未正确终止，缺少 )`,
                                line: keywordToken.line,
                                column: keywordToken.column,
                                token: keywordToken.value
                            });
                            this.skipToSemicolon();
                        }
                    }
                    
                    functionCall.params = params;
                } else {
                    this.skipToSemicolon();
                }
                
                // 处理可选的分号
                if (this.peek().value === ';') {
                    this.consume('punctuation');
                }
                
                return functionCall;
            } else {
                // 普通标识符的函数调用
                const statement = this.parseFunctionCall();
                // 处理可选的分号
                if (this.peek().value === ';') {
                    this.consume('punctuation');
                }
                
                return statement;
            }
        } 
        // 无法识别的语句
        else {
            const unexpectedToken = this.consume();
            this.errors.push({
                type: 'syntax',
                message: `意外的语句开始: ${unexpectedToken.type} '${unexpectedToken.value}'`,
                line: unexpectedToken.line,
                column: unexpectedToken.column,
                token: unexpectedToken.value
            });
            return {
                type: 'error',
                value: unexpectedToken.value,
                line: unexpectedToken.line,
                column: unexpectedToken.column
            };
        }
    }

    /**
     * 主解析函数
     * 解析整个标记序列，生成抽象语法树
     * @returns 包含AST和错误数组的对象
     */
    public parse(): { ast: TMakeASTNode[], errors: CompilerError[] } {
        const statements: TMakeASTNode[] = [];

        // 遍历所有标记，解析每个语句
        while (this.position < this.tokens.length) {
            try {
                const statement = this.parseStatement();
                // 只添加有效的语句到AST中
                if (statement && statement.type !== 'error' && statement.type !== 'empty') {
                    statements.push(statement);
                }

                // 跳过多余的分号
                while (this.position < this.tokens.length && this.peek().value === ';') {
                    this.consume('punctuation');
                }
            } catch (error) {
                // 错误恢复机制
                if (this.position < this.tokens.length) {
                    // 尝试跳到下一个语句开始
                while (this.position < this.tokens.length &&
                    this.peek().value !== ';' &&
                    this.peek().value !== '如果' &&
                    this.peek().value !== '假如') {
                    this.consume();
                }
                    if (this.peek().value === ';') {
                        this.consume('punctuation');
                    }
                }
            }
        }

        return { ast: statements, errors: this.errors };
    }
}